package com.quectel.util.thread;

import com.quectel.util.ex.CheckErrorException;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池帮助类
 *
 * @author: caolu
 * @email: louis.cao@quectel.com
 * @date: 2022-05-27 12:05:00
 */
public class ThreadPoolUtils {

    /**
     * 核心线程数cpu线程数+1
     */
    private static final int DEFAULT_CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() + 1;
    /**
     * 最大线程数量2*cpu线程数+1
     */
    private static final int DEFAULT_MAX_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2 + 1;

    /**
     * 默认存活时间默认60s
     */
    private static final int DEFAULT_KEEP_ALIVE_SECONDS = 60;

    /**
     * 默认队列大小
     */
    private static final int DEFAULT_QUEUE_SIZE = 1024;


    /**
     * 关闭线程池
     *
     * @param executor
     */
    public static void shutdown(ThreadPoolExecutor executor) {
        if (executor != null && !executor.isShutdown()) {
            executor.shutdown();
        }
    }


    /**
     * 获得一个新的线程池<br>
     * 传入阻塞系数，线程池的大小计算公式为：CPU可用核心数 / (1 - 阻塞因子)<br>
     * Blocking Coefficient(阻塞系数) = 阻塞时间／（阻塞时间+使用CPU的时间）<br>
     * 计算密集型任务的阻塞系数为0，而IO密集型任务的阻塞系数则接近于1。
     * <p>
     * see: http://blog.csdn.net/partner4java/article/details/9417663
     *
     * @param blockingCoefficient 阻塞系数，阻塞因子介于0~1之间的数，阻塞因子越大，线程池中的线程数越多。
     * @return {@link ThreadPoolExecutor}
     * @since 3.0.6
     */
    public static ThreadPoolExecutor newExecutorByBlockingCoefficient(String namePrefix, float blockingCoefficient) {
        if (blockingCoefficient >= 1 || blockingCoefficient < 0) {
            throw new CheckErrorException("线程池阻塞系数范围[0,,1)");
        }

        // 最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数)
        int poolSize = (int) (Runtime.getRuntime().availableProcessors() / (1 - blockingCoefficient));
        return new ThreadPoolExecutor(
                poolSize,
                poolSize,
                DEFAULT_KEEP_ALIVE_SECONDS,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(DEFAULT_QUEUE_SIZE),
                new NameThreadFactory(namePrefix),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }

    /**
     * 大多数情况所使用的的就是这个线程池 jvm关闭或者spring bean结束 必须shutdown 否则kill pid不能结束进程
     * <p>
     * io密集型 网络请求 DB 磁盘等操作 核心数量等于cpu数量的两倍+1
     *
     * @param namePrefix 线程池打印名称 submit-mock-data-pool-
     * @return
     */
    public static ThreadPoolExecutor createCommonIOBoundPool(String namePrefix) {
        return new ThreadPoolExecutor(
                DEFAULT_MAX_POOL_SIZE,
                DEFAULT_MAX_POOL_SIZE,
                DEFAULT_KEEP_ALIVE_SECONDS,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(DEFAULT_QUEUE_SIZE),
                new NameThreadFactory(namePrefix),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }


    /**
     * cpu密集型 核心数量等于cpu数量+1 jvm关闭或者spring bean结束 必须shutdown 否则kill pid不能结束进程
     *
     * @param namePrefix 线程池打印名称 submit-mock-data-pool-
     * @return
     */
    public static ThreadPoolExecutor createCommonCPUBoundPool(String namePrefix) {
        return new ThreadPoolExecutor(
                DEFAULT_CORE_POOL_SIZE,
                DEFAULT_MAX_POOL_SIZE,
                DEFAULT_KEEP_ALIVE_SECONDS,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(DEFAULT_QUEUE_SIZE),
                new NameThreadFactory(namePrefix),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }

    /**
     * 创建一个定时器 jvm关闭或者spring bean结束 必须shutdown 否则kill pid不能结束进程
     *
     * @param corePoolSize 核心线程池数量
     * @param namePrefix   线程池打印名称 submit-mock-data-pool-
     * @return
     */
    public static ScheduledThreadPoolExecutor createSchedulePool(int corePoolSize, String namePrefix) {
        return new ScheduledThreadPoolExecutor(corePoolSize, new NameThreadFactory(namePrefix));
    }
}
